﻿#region File Description
//-----------------------------------------------------------------------------
// ShoppingCart.cs
//
// Author: ITU Team3 (2012)
//-----------------------------------------------------------------------------
#endregion

#region Using Statements

using System;
using System.Collections.Generic;
using System.Linq;
using rentit03_server.Database;
#endregion

namespace rentit03_server.Business
{
    /// <summary>
    /// Class responsoble for the shoppingcart feature.
    /// A shoppingcart consists of a list of version ids bound to a user id.
    /// A shoppingcart is remembered between sessions/logins
    /// </summary>
    public static class ShoppingCart
    {
        // The cart used to keep track of users and their current shopping cart (user id -> list of version ids)
        private static readonly Dictionary<int, List<int>> Cart = new Dictionary<int, List<int>>();
        // Connection to data layer
        private static readonly DataAccessObject Dao = new DataAccessObject();

        /// <summary>
        /// Get current shoppingcart for a user
        /// </summary>
        /// <param name="sessionId">Session id used to identify the user</param>
        /// <returns>A list of version ids</returns>
        public static List<int> GetCart(string sessionId)
        {
            var id = SessionHandler.GetUser(sessionId).Id;

            if (!Cart.ContainsKey(id))
                return new List<int>();
            
            return Cart[id];
        }

        /// <summary>
        /// Add an item to the current shoppingcart.
        /// </summary>
        /// <param name="versionId">Version id of the item you want to add</param>
        /// <param name="sessionId">Session id</param>
        public static void AddToCart(int versionId, string sessionId)
        {
            var id = SessionHandler.GetUser(sessionId).Id;

            if(!Cart.ContainsKey(id))
                Cart.Add(id, new List<int>());
            
            Cart[id].Add(versionId);
        }

        /// <summary>
        /// Remove an item from the current shoppingcart.
        /// </summary>
        /// <param name="versionId">Version id of the item you want to remove</param>
        /// <param name="sessionId">Session id</param>
        public static void RemoveFromCart(int versionId, string sessionId)
        {
            var id = SessionHandler.GetUser(sessionId).Id;

            if(!Cart.ContainsKey(id))
                throw new RentitException(ReturnStatus.ShoppingcartNotFound, "No shoppingcart found for this session");
            
            if(!Cart[id].Remove(versionId))
                throw new RentitException(ReturnStatus.ShoppintcartItemNotFound, "Item not found");
        }

        /// <summary>
        /// Remove all items from the current shopping cart.
        /// </summary>
        /// <param name="sessionId">Session id</param>
        public static void ClearCart(string sessionId)
        {
            var uid = SessionHandler.GetUser(sessionId).Id;

            //Cart.Add(id, new List<int>());

            if (!Cart.ContainsKey(uid))
                throw new RentitException(ReturnStatus.ShoppingcartNotFound, "No shoppingcart found for this session");

            Cart[uid].Clear();
        }

        /// <summary>
        /// Purchase every item in the current shoppingcart.
        /// This will empty the shoppingcart.
        /// </summary>
        /// <param name="sessionId">Session id</param>
        /// <returns>A receipt object with information about the purchase. <see cref="rentit03_server.Business.RentitReceipt"/></returns>
        public static RentitReceipt CheckOutCart(string sessionId)
        {
            var uid = SessionHandler.GetUser(sessionId).Id;

            if (!Cart.ContainsKey(uid))
                throw new RentitException(ReturnStatus.ShoppingcartNotFound, "No shoppingcart found for this session");

            var dao = new DataAccessObject();

            foreach (var vid in Cart[uid])
            {
                var version = Dao.ReadVersion(vid);
                if (version == null)
                    throw new RentitException(ReturnStatus.MediaInvalidVersionId, "No version with id: " + vid);

                dao.Purchase(uid, vid, version.Price);
            }

            var r = GetReceipt(Cart[uid]);   // build receipt
            Cart[uid].Clear();       // empty cart
            return r;               // return receipt
        }

        /// <summary>
        /// Helper method for building the receipt
        /// </summary>
        /// <param name="versionIds">List of items</param>
        /// <returns>Receipt</returns>
        private static RentitReceipt GetReceipt(List<int> versionIds)
        {
            var dao = new DataAccessObject();
            var r = new RentitReceipt();

            foreach (var vid in versionIds)
            {
                var v = dao.ReadVersion(vid).ToRentitVersion();
                var m = dao.ReadMediaFromVersionId(vid);
                var url = MediaFileCreator.GetMediaFile(m);
                r.Add(new ReceiptItem(m.Id, m.Title, vid, v.Format, v.Price, url));
            }

            return r;
        }

        /// <summary>
        /// Get a list of all the users purchases.
        /// </summary>
        /// <param name="sessionId">Session id</param>
        /// <returns>A list of purchases. <see cref="rentit03_server.Business.RentitPurchase"/></returns>
        public static List<RentitPurchase> OverviewPurchases(string sessionId)
        {
            var id = SessionHandler.GetUser(sessionId).Id;
            var purchases = Dao.OverviewPurchases(id);

            return purchases.Select(p => p.ToRentitPurchase()).ToList();
        }

        /// <summary>
        /// Convert a Purchase to a RentitPurchase
        /// </summary>
        /// <param name="purchase">A Purchase in Data Layer format</param>
        /// <returns>A RentitPurchase</returns>
        private static RentitPurchase ToRentitPurchase(this Purchase purchase)
        {
            return new RentitPurchase
            {
                Id = purchase.Id,
                StartTime = purchase.StartTime.ToString(),
                EndTime = purchase.EndTime.ToString(),
                UserId = purchase.UserId,
                VersionId = purchase.VersionId
            };
        }
    }

    /// <summary>
    /// Class for representing a purchase
    /// </summary>
    public class RentitPurchase
    {
        public int Id { get; set; }
        public string StartTime { get; set; }
        public string EndTime { get; set; }
        public int UserId { get; set; }
        public int VersionId { get; set; }
    }

    /// <summary>
    /// An item on a receipt
    /// </summary>
    public class ReceiptItem
    {
        public ReceiptItem(int mediaId, string title, int versionId, string format, int cost, string downloadUrl = "")
        {
            DownloadUrl = downloadUrl;
            Cost = cost;
            Format = format;
            VersionId = versionId;
            Title = title;
            MediaId = mediaId;
        }

        public int MediaId { get; private set; }
        public string Title { get; private set; }
        public int VersionId { get; private set; }
        public string Format { get; private set; }
        public string DownloadUrl { get; private set; }
        public int Cost { get; private set; }
    }

    /// <summary>
    /// A receipt.
    /// Contains a list of ReceiptItems and a total cost.
    /// </summary>
    public class RentitReceipt
    {
        public List<ReceiptItem> Items { get; set; }
        public int TotalCost { get; set; }

        public void Add(ReceiptItem item)
        {
            if(Items == null)
                Items = new List<ReceiptItem>();

            Items.Add(item);
            TotalCost += item.Cost;
        }
    }
}